import os
import random
import string
from PIL import Image, ImageFont, ImageDraw, ImageFilter
import io


class ImageVerify:

    def __init__(self, x=140, y=40, length=4, size=28):
        """
        初始化方法
        :param x: 图片的宽度 px 像素
        :param y: 图片的高度
        :param length: 文字的个数
        :param size:  字体的大小 px
        """
        self.x = x
        self.y = y
        self.length = length
        self.size = size

    # 生成图片里面的随机文字
    def random_str(self):
        """
        随机生成指定长度的字符串
        验证码的文字：字母+数字组成
        :return: 返回生成的四个字符
        """
        # 所有的字母+所有的数字 随机字符的范围
        source = string.ascii_letters + string.digits
        # 从以上的范围里面随机挑出四个字符
        result = ''.join(random.sample(source, self.length))
        # print(result)
        return result

    # 随机生成文字的颜色 0-255
    def random_color(self, start=0, end=255):
        """
        随机生成rgb（红绿蓝）颜色
        rgb（100,25,30）
        :param start: 颜色范围的最小值
        :param end: 颜色范围的最大值
        :return: 颜色值的元祖
        """
        result = [random.randint(start, end) for i in range(3)]
        # 转元祖类型
        return tuple(result)

    # 生成干扰线 在画布上进行绘画 通过两个点确定一条线
    def random_lines(self, draw):
        """
        绘制干扰线
        :param draw: 画笔对象
        :return: 没有返回值 调用时进行绘画的操作
        """
        # 根据文字个数来决定绘制线条条数
        for i in range(self.length):
            # 干扰线的起点 x轴 y轴范围
            lines = [(random.randint(0, self.x), random.randint(0, self.y)) for i in range(2)]
            # 通过画笔对象 调用画线条的方法 fill指定线条的颜色
            draw.line(lines, fill=self.random_color(64, 200))

    # 生成干扰点
    def random_points(self, draw, rate):
        """
        绘制干扰点
        :param draw: 画笔对象
        :param rate: 生成干扰点的频率 密集性
        :return: 没有返回值 调用时进行绘画的操作
        """
        # 得到每个像素点
        for x in range(self.x):
            for y in range(self.y):
                if random.randint(1, 100) <= rate:
                    draw.point((x, y), fill=self.random_color(64, 200))

    # 组装成一张验证码的图片
    def verify_code(self):
        """
        生成验证码图片 组成以上多个方法
        :return: 返回验证码图片对象
        """
        # 创建一个画布对象 颜色通道 画布宽高 白色背景颜色
        image = Image.new('RGB', (self.x, self.y), (255, 255, 255))
        # 创建font对象 字体
        # 需要用的字体文件
        # os.path.abspath(__file__) 当前脚本所在文件的绝对地址
        # D:\yulin\workspace\django_git\workspace\DRFStudy_34\utils\verifyUtil.py
        # os.path.dirname 去除掉文件名 只保留文件夹的路径
        # D:\yulin\workspace\django_git\workspace\DRFStudy_34\utils\
        file = os.path.dirname(os.path.abspath(__file__))
        font = ImageFont.truetype(f'{file}/HYYakuHei-85W.ttf', self.size)  # 字体类型,字体大小
        # 创建画笔对象 在画布上创建画笔
        draw = ImageDraw.Draw(image)

        # 绘制干扰线和干扰点
        self.random_lines(draw)
        self.random_points(draw, 50)

        # 绘制答案
        code = self.random_str()
        # 验证码的答案应该要写在什么地方
        for i in range(self.length):
            # 绘制文字  坐标 字符内容 字体 颜色
            draw.text((35 * i + 5, random.randint(3, 6)), code[i], font=font, fill=self.random_color(32, 127))
            # 高斯模糊滤镜
            image.filter(ImageFilter.BLUR)
        return image, code


# 添加生成短信验证码的函数
def generate_sms_code(length=6):
    """
    生成短信验证码
    :param length: 验证码长度，默认6位
    :return: 随机数字组成的字符串
    """
    # 生成指定长度的随机数字字符串
    code = ''.join(random.choices(string.digits, k=length))
    return code


# 或者使用另一种实现方式
def generate_sms_code_v2(length=6):
    """
    生成短信验证码（另一种实现方式）
    :param length: 验证码长度，默认6位
    :return: 随机数字组成的字符串
    """
    code = ""
    for _ in range(length):
        code += str(random.randint(0, 9))
    return code


# 判断 运行时 是该文件本身在运行还是其他文件导入了这个模块在运行
# 当其他的文件导入该文件模块运行 并不会执行判断里面的代码
if __name__ == '__main__':
    img = ImageVerify()
    image, code = img.verify_code()
    with open('code.png', 'wb') as fp:
        image.save(fp)
    print(code)
